package org.rsbot.script;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.rsbot.bot.Bot;
import org.rsbot.client.Client;
import org.rsbot.script.wrappers.RSInterface;
import org.rsbot.script.wrappers.RSInterfaceChild;


public class Interfaces {
    
    private RSInterface[] mainCache = new RSInterface[0];
 // If it doesn't fit in the above cache.
    private final Map<Integer, RSInterface> sparseMap = new HashMap<Integer, RSInterface>();
    
    private final Bot bot;

    public Interfaces(final Bot bot) {
        this.bot = bot;
    }

    /**
     * @return All the valid interfaces.
     * */
    public synchronized RSInterface[] getAllInterfaces() {
        enlargeCache();
        final org.rsbot.client.RSInterface[][] inters = bot.getClient().getRSInterfaceCache();
        if (inters == null)
            return new RSInterface[0];
        final List<RSInterface> out = new ArrayList<RSInterface>();
        for (int i = 0; i < inters.length; i++) {
            if (inters[i] != null) {
                final RSInterface in = getInterface(i);
                if (in.isValid()) {
                    out.add(in);
                }
            }
        }
        return out.toArray(new RSInterface[out.size()]);
    }
    
    public RSInterfaceChild getChildInterface(final int id) {
        final int x = id >> 16;
        final int y = id & 0xFFFF;

        return getInterface(x).getChild(y);
    }
    
    /**
     * @param index, The parent interface index
     * @param indexChild, The child interface index
     * @return The child for the given index and indexChild
     * */
    public RSInterfaceChild getChildInterface(final int index, final int indexChild) {
        return getInterface(index).getChild(indexChild);
    }
    
    /**
     * @param index The index of the interface.
     * @return The interface for the given index.
     * */
    public synchronized RSInterface getInterface(final int index) {
        RSInterface inter;
        final int cacheLen = mainCache.length;
        if (index < cacheLen) {
            inter = mainCache[index];
            if (inter == null) {
                inter = new RSInterface(index, true, bot);
                mainCache[index] = inter;
            }
        } else {
            inter = sparseMap.get(index);
            if (inter == null) {
                enlargeCache();
                if (index < cacheLen) {
                    inter = mainCache[index];
                    if (inter == null) {
                        inter = new RSInterface(index, true, bot);
                        mainCache[index] = inter;
                    }
                } else {
                    inter = new RSInterface(index, true, bot);
                    sparseMap.put(index, inter);
                }
            }
        }
        return inter;
    }
    
    /**
     * @return The maximum *known* interface cache size.
     * */
    public synchronized int getMaxInterfaceCacheSize() {
        enlargeCache();
        return mainCache.length;
    }
    
    /**
     * Enlarges the cache if there are more interfaces than the cache size.
     */
    private synchronized void enlargeCache() {
        final Client c = bot.getClient();
        if (c == null)
            return;
        final org.rsbot.client.RSInterface[][] inters = c.getRSInterfaceCache();
        if ((inters != null) && (mainCache.length < inters.length)) { // enlarge
            // cache
            mainCache = Arrays.copyOf(mainCache, inters.length);
            for (int i = mainCache.length; i < mainCache.length; i++) {
                final RSInterface tmp = sparseMap.get(i);
                if (tmp != null) {
                    sparseMap.remove(i);
                    mainCache[i] = tmp;
                }
            }
        }
    }
}
